package com.recognition.webcam;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

import com.lti.civil.CaptureDeviceInfo;
import com.lti.civil.CaptureException;
import com.lti.civil.CaptureStream;
import com.lti.civil.CaptureSystem;
import com.lti.civil.CaptureSystemFactory;
import com.lti.civil.DefaultCaptureSystemFactorySingleton;
import com.lti.civil.VideoFormat;
import com.recognition.Logger;
import com.recognition.swing.JVideoPanel;
import javax.swing.JCheckBox;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Webcam extends JFrame
{
	private static Logger _log = Logger.getLogger();
	
	private static Webcam frame;
	private JPanel contentPane;
	private JVideoPanel imagePanel;
	
	private CaptureSystemFactory factory;
	private CaptureSystem system;
	private CaptureDeviceInfo webcam;
	private CaptureStream captureStream;
	private SnapshotObserver observer;
		
	public static void initialize()
	{
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e1) {
			e1.printStackTrace();
		} catch (InstantiationException e1) {
			e1.printStackTrace();
		} catch (IllegalAccessException e1) {
			e1.printStackTrace();
		} catch (UnsupportedLookAndFeelException e1) {
			e1.printStackTrace();
		}		
		
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					frame = new Webcam();					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
	/**
	 * Create the frame.
	 */
	public Webcam()
	{
		setTitle("Recognition Client: Live Webcam");
		
		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		setBounds(0, 0, 402, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		imagePanel = new JVideoPanel();		
		contentPane.add(imagePanel, BorderLayout.CENTER);	
		
		setResizable(false);
	}	
	
	public void updateFrame(BufferedImage img)
	{
		if (isVisible())
			imagePanel.setFrame(img);	
	}
	
	public void connect()
	{	
		factory = DefaultCaptureSystemFactorySingleton.instance();
		List<CaptureDeviceInfo> list = null;
		try 
		{
			system = factory.createCaptureSystem();
			system.init();
			list = system.getCaptureDeviceInfoList();
		} catch (CaptureException e) {
			_log.error("Webcam: Failed to retreive list of webcams");
			_log.error("Webcam: " + e.getMessage());
		}
		
		if (list == null || list.size() == 0)
		{
			_log.info("Webcam: No webcams available");
			return;
		}
		
		webcam = list.get(0);		
		
		try 
		{	
			captureStream = system.openCaptureDeviceStream(webcam.getDeviceID());
			
			VideoFormat newFormat = captureStream.getVideoFormat();
			VideoFormat prevFormat = newFormat;
			
			int minWidth = 9999;
			
			for (VideoFormat format : captureStream.enumVideoFormats())
			{
				if (format.getWidth() < minWidth && format.getWidth() != 0)
				{
					minWidth = format.getWidth();
					newFormat = format;
				}
			}
						
			if (!newFormat.equals(prevFormat) && newFormat.getWidth() != 0)
				captureStream.setVideoFormat(newFormat);
						
			int width = captureStream.getVideoFormat().getWidth();
			int height = captureStream.getVideoFormat().getHeight();
			if (width < 200)
				setBounds(0, 0, 2*width + 10, 2*height + 10);
			else
				setBounds(0, 0, width + 10, height + 10);
			
		} catch (CaptureException e) {
			_log.error("Webcam: Failed to connect to " + webcam.getDescription());
			_log.error("Webcam: " + e.getMessage());
			return;
		}
		
		observer = new SnapshotObserver(this);
		captureStream.setObserver(observer);
		
		_log.info("Webcam: Connected to " + webcam.getDescription());
		
		start();
	}
	
	public void close()
	{
		if (captureStream != null)
		{
			try 
			{
				captureStream.stop();
				captureStream.dispose();
			} catch (CaptureException e) {
				_log.error("Webcam: Failed to close webcam");
				_log.error("Webcam: " + e.getMessage());
			}			
		}
		
		if (system != null)
		{
			try 
			{
				system.dispose();
			} catch (CaptureException e) {
				_log.error("Webcam: Failed to close webcam");
				_log.error("Webcam: " + e.getMessage());
			}	
		}
	}
	
	public void capturePicture(boolean reference)
	{
		observer.capturePicture(reference);
	}
	
	public boolean start()
	{
		try 
		{				
			captureStream.start();			
		}
		catch (CaptureException e)
		{
			_log.error("Webcam: Failed to start capturing");
			_log.error("Webcam: " + e.getMessage());

			e.printStackTrace();
			return false;
		}
		
		return true;
	}
	
	public boolean stop()
	{
		try 
		{				
			captureStream.stop();
		}
		catch (CaptureException e)
		{
			_log.error("Webcam: Failed to stop capturing");
			_log.error("Webcam: " + e.getMessage());
			return false;
		}
		
		return true;
	}	

	public static String videoFormatToString(VideoFormat f)
	{
		return "Type=" + formatTypeToString(f.getFormatType()) + " Width=" + f.getWidth() + " Height=" + f.getHeight() + " FPS=" + f.getFPS();
	}

	private static String formatTypeToString(int f)
	{
		switch (f)
		{
			case VideoFormat.RGB24:
				return "RGB24";
			case VideoFormat.RGB32:
				return "RGB32";
			default:
				return "" + f + " (unknown)";
		}
	}
	
	public static Webcam getWebcam()
	{
		return frame;
	}
	
	public void updatePos(int x, int y)
	{
		setBounds(x, y, getWidth(), getHeight());
	}
}